package com.gzc.just.play.last.war.common.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Game service
 * Provides core game functionality
 */
@Service
public class GameService {
    
    private static final Logger log = LoggerFactory.getLogger(GameService.class);
    
    // Player data cache
    private final ConcurrentHashMap<Long, Player> playerData = new ConcurrentHashMap<>();
    
    // Game configuration
    private final Map<String, Object> gameConfig = new ConcurrentHashMap<>();
    
    /**
     * Get player data
     * @param playerId Player ID
     * @return Player data
     */
    public Player getPlayer(Long playerId) {
        return playerData.get(playerId);
    }
    
    /**
     * Save player data
     * @param player Player data
     */
    public void savePlayer(Player player) {
        playerData.put(player.getId(), player);
        log.debug("Saved player data for ID: {}", player.getId());
    }
    
    /**
     * Get game configuration
     * @param key Configuration key
     * @return Configuration value
     */
    @SuppressWarnings("unchecked")
    public <T> T getConfig(String key, Class<T> type) {
        Object value = gameConfig.get(key);
        if (value != null && type.isInstance(value)) {
            return (T) value;
        }
        return null;
    }
    
    /**
     * Set game configuration
     * @param key Configuration key
     * @param value Configuration value
     */
    public void setConfig(String key, Object value) {
        gameConfig.put(key, value);
        log.info("Updated game config: {} = {}", key, value);
    }
    
    /**
     * Create new player
     * @param playerId Player ID
     * @param name Player name
     * @return New player object
     */
    public Player createPlayer(Long playerId, String name) {
        Player player = new Player(playerId, name);
        savePlayer(player);
        log.info("Created new player: ID={}, Name={}", playerId, name);
        return player;
    }
    
    /**
     * Notify player
     * @param playerId Player ID
     * @param data Notification data
     */
    public void notifyPlayer(Long playerId, Map<String, Object> data) {
        Player player = getPlayer(playerId);
        if (player != null) {
            // In a real implementation, this would send a message to the player's client
            log.info("Notified player {}: {}", playerId, data);
        }
    }
    
    /**
     * Player entity class
     */
    public static class Player {
        private final Long id;
        private final String name;
        private int level;
        private long experience;
        private int health;
        private int maxHealth;
        private int attack;
        private int defense;
        private long lastOnlineTime;
        
        public Player(Long id, String name) {
            this.id = id;
            this.name = name;
            this.level = 1;
            this.experience = 0;
            this.health = 100;
            this.maxHealth = 100;
            this.attack = 10;
            this.defense = 5;
            this.lastOnlineTime = System.currentTimeMillis();
        }
        
        public Long getId() {
            return id;
        }
        
        public String getName() {
            return name;
        }
        
        public int getLevel() {
            return level;
        }
        
        public void setLevel(int level) {
            this.level = Math.max(1, level);
        }
        
        public long getExperience() {
            return experience;
        }
        
        public void setExperience(long experience) {
            this.experience = Math.max(0, experience);
        }
        
        public int getHealth() {
            return health;
        }
        
        public void setHealth(int health) {
            this.health = Math.max(0, Math.min(health, maxHealth));
        }
        
        public int getMaxHealth() {
            return maxHealth;
        }
        
        public void setMaxHealth(int maxHealth) {
            this.maxHealth = Math.max(1, maxHealth);
            if (health > maxHealth) {
                health = maxHealth;
            }
        }
        
        public int getAttack() {
            return attack;
        }
        
        public void setAttack(int attack) {
            this.attack = Math.max(1, attack);
        }
        
        public int getDefense() {
            return defense;
        }
        
        public void setDefense(int defense) {
            this.defense = Math.max(0, defense);
        }
        
        public long getLastOnlineTime() {
            return lastOnlineTime;
        }
        
        public void setLastOnlineTime(long lastOnlineTime) {
            this.lastOnlineTime = lastOnlineTime;
        }
        
        /**
         * Add experience
         * @param amount Experience amount
         */
        public void addExperience(long amount) {
            this.experience += amount;
            checkLevelUp();
        }
        
        /**
         * Check level up
         */
        private void checkLevelUp() {
            int requiredExp = calculateRequiredExp(level);
            if (experience >= requiredExp) {
                level++;
                experience -= requiredExp;
                maxHealth += 10;
                health = maxHealth;
                attack += 2;
                defense += 1;
            }
        }
        
        /**
         * Calculate required experience
         * @param level Level
         * @return Required experience
         */
        private int calculateRequiredExp(int level) {
            return level * 100 + level * level * 10; // Simple formula
        }
        
        /**
         * Heal health
         * @param amount Heal amount
         */
        public void heal(int amount) {
            health = Math.min(health + amount, maxHealth);
        }
        
        /**
         * Take damage
         * @param damage Damage value
         * @return Actual damage value
         */
        public int takeDamage(int damage) {
            int actualDamage = Math.max(1, damage - defense / 2); // Defense reduces damage
            health = Math.max(0, health - actualDamage);
            return actualDamage;
        }
        
        /**
         * Check if alive
         * @return Whether alive
         */
        public boolean isAlive() {
            return health > 0;
        }
    }
}